/**
 * Software License, Version 1.0
 * 
 * Copyright 2003 The Trustees of Indiana University.  All rights reserved.
 * 
 *
 *Redistribution and use in source and binary forms, with or without 
 *modification, are permitted provided that the following conditions are met:
 *
 *1) All redistributions of source code must retain the above copyright notice,
 * the list of authors in the original source code, this list of conditions and
 * the disclaimer listed in this license;
 *2) All redistributions in binary form must reproduce the above copyright 
 * notice, this list of conditions and the disclaimer listed in this license in
 * the documentation and/or other materials provided with the distribution;
 *3) Any documentation included with all redistributions must include the 
 * following acknowledgement:
 *
 *"This product includes software developed by the Community Grids Lab. For 
 * further information contact the Community Grids Lab at 
 * http://communitygrids.iu.edu/."
 *
 * Alternatively, this acknowledgement may appear in the software itself, and 
 * wherever such third-party acknowledgments normally appear.
 * 
 *4) The name Indiana University or Community Grids Lab or NaradaBrokering, 
 * shall not be used to endorse or promote products derived from this software 
 * without prior written permission from Indiana University.  For written 
 * permission, please contact the Advanced Research and Technology Institute 
 * ("ARTI") at 351 West 10th Street, Indianapolis, Indiana 46202.
 *5) Products derived from this software may not be called NaradaBrokering, 
 * nor may Indiana University or Community Grids Lab or NaradaBrokering appear
 * in their name, without prior written permission of ARTI.
 * 
 *
 * Indiana University provides no reassurances that the source code provided 
 * does not infringe the patent or any other intellectual property rights of 
 * any other entity.  Indiana University disclaims any liability to any 
 * recipient for claims brought by any other entity based on infringement of 
 * intellectual property rights or otherwise.  
 *
 *LICENSEE UNDERSTANDS THAT SOFTWARE IS PROVIDED "AS IS" FOR WHICH NO 
 *WARRANTIES AS TO CAPABILITIES OR ACCURACY ARE MADE. INDIANA UNIVERSITY GIVES
 *NO WARRANTIES AND MAKES NO REPRESENTATION THAT SOFTWARE IS FREE OF 
 *INFRINGEMENT OF THIRD PARTY PATENT, COPYRIGHT, OR OTHER PROPRIETARY RIGHTS. 
 *INDIANA UNIVERSITY MAKES NO WARRANTIES THAT SOFTWARE IS FREE FROM "BUGS", 
 *"VIRUSES", "TROJAN HORSES", "TRAP DOORS", "WORMS", OR OTHER HARMFUL CODE.  
 *LICENSEE ASSUMES THE ENTIRE RISK AS TO THE PERFORMANCE OF SOFTWARE AND/OR 
 *ASSOCIATED MATERIALS, AND TO THE PERFORMANCE AND VALIDITY OF INFORMATION 
 *GENERATED USING SOFTWARE.
 */
package cgl.narada.service.security.impl;

import java.security.KeyPair;
import java.security.MessageDigest;
import java.security.PrivateKey;
import java.security.Provider;
import java.security.PublicKey;
import java.security.SecureRandom;
import java.security.Security;
import java.security.Signature;
import java.util.Hashtable;

import javax.crypto.Cipher;
import javax.crypto.SecretKey;
import javax.crypto.spec.IvParameterSpec;

import org.bouncycastle.jce.provider.BouncyCastleProvider;

import cgl.narada.service.ServiceException;
import cgl.narada.service.security.EntityOperations;

/**
 * This interface encapsulates the set of operations that need to be performed
 * to ensure secure messaging. $Date$ $Revision$
 */
public class EntityOperationsImpl implements EntityOperations {
    public Hashtable providers;
    private String moduleName = "EntityOperationsImpl: ";

    public EntityOperationsImpl() throws ServiceException {
        providers = new Hashtable();

        Provider cryptixCrypto = new cryptix.jce.provider.CryptixCrypto();
        Provider bouncyCastle = new BouncyCastleProvider();

        try {
            Security.addProvider(cryptixCrypto);
            providers.put("CryptixCrypto", cryptixCrypto);

            Security.addProvider(bouncyCastle);
            providers.put("BC", bouncyCastle);

        } catch (SecurityException serEx) {
            throw new ServiceException(moduleName + serEx);
        }
    }

    // HG: ------------------------------------------------------------

    public byte[] getIV(String alg, String mode, String padding)
            throws ServiceException {
        try {
            Cipher cipher = Cipher
                    .getInstance(alg + "/" + mode + "/" + padding);

            byte[] iv = null;

            if (mode != "ECB") {
                SecureRandom sr = new SecureRandom();
                // allocate memory for iv.
                iv = new byte[cipher.getBlockSize()];
                // Get next bytes from the PRNG.
                sr.nextBytes(iv);
            }

            return iv;
        } catch (Exception e) {
            throw new ServiceException(moduleName + "Problems generating "
                    + "Initialization Vector (IV) " + e);
        } /* end try-catch */

    }

    /* Encrypt message with the topic's symmetric key */
    public byte[] encryptPayload(SecretKey secretTopicKey, byte[] messageBytes,
            String algModePadding, byte[] iv, String provider)
            throws ServiceException {
        byte[] encryptedData = null;
        try {
            Cipher cipher = Cipher.getInstance(algModePadding, provider);
            IvParameterSpec spec = new IvParameterSpec(iv);

            cipher.init(Cipher.ENCRYPT_MODE, secretTopicKey, spec);
            encryptedData = cipher.doFinal(messageBytes);
        } catch (Exception e) {
            e.printStackTrace();
            throw new ServiceException(moduleName + e);
        }
        return encryptedData;
    }

    /* Decrypt message with the topic's symmetric key */
    public byte[] decryptPayload(SecretKey secretTopicKey,
            byte[] encryptedBytes, String algModePadding, byte[] iv,
            String provider) throws ServiceException {
        byte[] decryptedBytes = null;
        try {
            Cipher cipher = Cipher.getInstance(algModePadding, provider);

            IvParameterSpec spec = new IvParameterSpec(iv);

            cipher.init(Cipher.DECRYPT_MODE, secretTopicKey, spec);
            decryptedBytes = cipher.doFinal(encryptedBytes);
        } catch (Exception e) {
            throw new ServiceException(moduleName + e);
        }
        return decryptedBytes;
    }

    // ------------------------------------------------
    public static String str = "/NONE/PKCS1Padding";
    public static String providerToUse = "BC";
    /* Encrypt message with the topic's public key */
    public byte[] encryptPayload(PublicKey publicTopicKey, byte[] messageBytes)
            throws ServiceException {
        byte[] encryptedData = null;

	System.out.println("Encrypting MEssage Size: " + messageBytes.length + " bytes");

        try {
            Cipher cipher = Cipher.getInstance(publicTopicKey.getAlgorithm()
				 + str, providerToUse);
	    
            cipher.init(Cipher.ENCRYPT_MODE, publicTopicKey);
            encryptedData = cipher.doFinal(messageBytes);
        } catch (Exception e) {
            throw new ServiceException(moduleName
                    + "Error while encrypting payload-> " + e);
        }
        return encryptedData;
    }

    /* Decrypt message with the private key */
    public byte[] decryptPayload(PrivateKey privateTopicKey,
            byte[] encryptedBytes) throws ServiceException {
        byte[] decryptedBytes = null;
        try {
            Cipher cipher = Cipher.getInstance(privateTopicKey.getAlgorithm()
				   + str, providerToUse);
            cipher.init(Cipher.DECRYPT_MODE, privateTopicKey);
            decryptedBytes = cipher.doFinal(encryptedBytes);
        } catch (Exception e) {
            throw new ServiceException(moduleName + "Error decrypting payload "
                    + e);
        }
        return decryptedBytes;
    }

    /* Encrypt message with the topic's public key */
    public byte[] encryptPayload(PublicKey publicTopicKey, String mode,
            String padding, byte[] payloadBytes) throws ServiceException {
        byte[] encryptedData = null;
        try {
            String algorithm = publicTopicKey.getAlgorithm();
            Cipher cipher = Cipher.getInstance(algorithm + "/" + mode + "/"
                    + padding);

            cipher.init(Cipher.ENCRYPT_MODE, publicTopicKey);
            encryptedData = cipher.doFinal(payloadBytes);
        } catch (Exception e) {
            throw new ServiceException(moduleName
                    + "Error while encrypting payload-> " + e);
        }
        return encryptedData;
    }

    /* Encrypt message with the topic's public key */
    public byte[] encryptPayload(PublicKey publicTopicKey, String mode,
            String padding, String provider, byte[] payloadBytes)
            throws ServiceException {
        byte[] encryptedData = null;
        try {
            String algorithm = publicTopicKey.getAlgorithm();
            Cipher cipher = Cipher.getInstance(algorithm + "/" + mode + "/"
                    + padding, provider);

            cipher.init(Cipher.ENCRYPT_MODE, publicTopicKey);
            encryptedData = cipher.doFinal(payloadBytes);
        } catch (Exception e) {
            throw new ServiceException(moduleName
                    + "Error while encrypting payload-> " + e);
        }
        return encryptedData;
    }

    /* Decrypt message with the private key */
    public byte[] decryptPayload(PrivateKey privateTopicKey, String mode,
            String padding, byte[] encryptedBytes) throws ServiceException {
        byte[] decryptedBytes = null;
        try {
            String algorithm = privateTopicKey.getAlgorithm();
            Cipher cipher = Cipher.getInstance(algorithm + "/" + mode + "/"
                    + padding);

            cipher.init(Cipher.DECRYPT_MODE, privateTopicKey);
            decryptedBytes = cipher.doFinal(encryptedBytes);
        } catch (Exception e) {
            throw new ServiceException(moduleName + "Error decrypting payload "
                    + e);
        }
        return decryptedBytes;
    }

    /* Decrypt message with the private key */
    public byte[] decryptPayload(PrivateKey privateTopicKey, String mode,
            String padding, String provider, byte[] encryptedBytes)
            throws ServiceException {
        byte[] decryptedBytes = null;
        try {
            String algorithm = privateTopicKey.getAlgorithm();
            Cipher cipher = Cipher.getInstance(algorithm + "/" + mode + "/"
                    + padding, provider);

            cipher.init(Cipher.DECRYPT_MODE, privateTopicKey);
            decryptedBytes = cipher.doFinal(encryptedBytes);
        } catch (Exception e) {
            throw new ServiceException(moduleName + "Error decrypting payload "
                    + e);
        }
        return decryptedBytes;
    }

    /* Encrypt message with the topic's symmetric key */
    public byte[] encryptPayload(SecretKey secretTopicKey, byte[] messageBytes)
            throws ServiceException {
        byte[] encryptedData = null;
        try {
            Cipher cipher = Cipher.getInstance(secretTopicKey.getAlgorithm()
                    + "/" + "CBC" + "/" + "PKCS#5");

            IvParameterSpec spec = null; // initialization vector
            byte[] iv = null; // initialization vector as byte[]

            SecureRandom sr = new SecureRandom();
            iv = new byte[cipher.getBlockSize()];
            sr.nextBytes(iv);
            spec = new IvParameterSpec(iv);

            cipher.init(Cipher.ENCRYPT_MODE, secretTopicKey, spec);
            encryptedData = cipher.doFinal(messageBytes);
        } catch (Exception e) {
            e.printStackTrace();
            throw new ServiceException(moduleName + e);
        }
        return encryptedData;
    }

    /* Decrypt message with the topic's symmetric key */
    public byte[] decryptPayload(SecretKey secretTopicKey, byte[] encryptedBytes)
            throws ServiceException {
        byte[] decryptedBytes = null;
        try {
            Cipher cipher = Cipher.getInstance(secretTopicKey.getAlgorithm()
                    + "/" + "CBC" + "/" + "PKCS#5");
            // Cipher cipher =
            // Cipher.getInstance(secretTopicKey.getAlgorithm());

            IvParameterSpec spec = null; // initialization vector
            byte[] iv = null; // initialization vector as byte[]

            // SecureRandom sr = new SecureRandom();
            // iv = new byte[cipher.getBlockSize()];
            // sr.nextBytes(iv);
            iv = cipher.getIV();
            spec = new IvParameterSpec(iv);

            cipher.init(Cipher.DECRYPT_MODE, secretTopicKey, spec);
            decryptedBytes = cipher.doFinal(encryptedBytes);
        } catch (Exception e) {
            throw new ServiceException(moduleName + e);
        }
        return decryptedBytes;
    }

    public byte[] getIV(SecretKey secretTopicKey, String mode, String padding)
            throws ServiceException {
        try {
            String algorithm = secretTopicKey.getAlgorithm();
            Cipher cipher = Cipher.getInstance(algorithm + "/" + mode + "/"
                    + padding);

            byte[] iv = null;

            if (mode != "ECB") {
                SecureRandom sr = new SecureRandom();
                // allocate memory for iv.
                iv = new byte[cipher.getBlockSize()];
                // Get next bytes from the PRNG.
                sr.nextBytes(iv);
            }

            return iv;
        } catch (Exception e) {
            throw new ServiceException(moduleName + "Problems generating "
                    + "Initialization Vector (IV) " + e);
        } /* end try-catch */

    }

    public byte[] getIV(SecretKey secretTopicKey, String mode, String padding,
            String provider) throws ServiceException {
        try {
            String algorithm = secretTopicKey.getAlgorithm();
            Cipher cipher = Cipher.getInstance(algorithm + "/" + mode + "/"
                    + padding, provider);

            byte[] iv = null;

            if (mode != "ECB") {
                SecureRandom sr = new SecureRandom();
                // allocate memory for iv.
                iv = new byte[cipher.getBlockSize()];
                // Get next bytes from the PRNG.
                sr.nextBytes(iv);
            }

            return iv;
        } catch (Exception e) {
            throw new ServiceException(moduleName + "Problems generating "
                    + "Initialization Vector (IV) " + e);
        } /* end try-catch */

    }

    public byte[] encryptPayload(SecretKey secretTopicKey, String mode,
            String padding, byte[] payloadBytes, byte[] iv)
            throws ServiceException {
        try {
            String algorithm = secretTopicKey.getAlgorithm();
            Cipher cipher = Cipher.getInstance(algorithm + "/" + mode + "/"
                    + padding);
            IvParameterSpec spec = null; // initialization vector

            if (mode == "ECB") {
                cipher.init(Cipher.ENCRYPT_MODE, secretTopicKey);
            } else {
                spec = new IvParameterSpec(iv);
                /* use encryption mode using specified key and IV. */
                cipher.init(Cipher.ENCRYPT_MODE, secretTopicKey, spec);
            }

            byte[] encryptedPayloadBytes = cipher.doFinal(payloadBytes);
            return encryptedPayloadBytes;
        } catch (Exception e) {
            throw new ServiceException(moduleName
                    + "Problems encrypting payload" + e);
        }/* end try-catch */
    }

    public byte[] encryptPayload(SecretKey secretTopicKey, String mode,
            String padding, String provider, byte[] payloadBytes, byte[] iv)
            throws ServiceException {
        try {
            String algorithm = secretTopicKey.getAlgorithm();
            Cipher cipher = Cipher.getInstance(algorithm + "/" + mode + "/"
                    + padding, provider);
            IvParameterSpec spec = null; // initialization vector

            if (mode == "ECB") {
                cipher.init(Cipher.ENCRYPT_MODE, secretTopicKey);
            } else {
                spec = new IvParameterSpec(iv);
                /* use encryption mode using specified key and IV. */
                cipher.init(Cipher.ENCRYPT_MODE, secretTopicKey, spec);
            }

            byte[] encryptedPayloadBytes = cipher.doFinal(payloadBytes);
            return encryptedPayloadBytes;
        } catch (Exception e) {
            throw new ServiceException(moduleName
                    + "Problems encrypting payload" + e);
        }/* end try-catch */
    }

    public byte[] decryptPayload(SecretKey secretTopicKey, String mode,
            String padding, byte[] encryptedPayloadBytes, byte[] iv)
            throws ServiceException {
        try {
            String algorithm = secretTopicKey.getAlgorithm();
            Cipher decipher = Cipher.getInstance(algorithm + "/" + mode + "/"
                    + padding);
            IvParameterSpec spec = null; // initialization vector

            if (mode != "ECB") {
                spec = new IvParameterSpec(iv);
            }

            decipher.init(Cipher.DECRYPT_MODE, secretTopicKey, spec);
            byte[] decryptedPayloadBytes = decipher
                    .doFinal(encryptedPayloadBytes);
            return decryptedPayloadBytes;

        } catch (Exception e) {
            throw new ServiceException(moduleName
                    + "Problems decrypting payload" + e);
        }/* end try-catch */
    }

    public byte[] decryptPayload(SecretKey secretTopicKey, String mode,
            String padding, String provider, byte[] encryptedPayloadBytes,
            byte[] iv) throws ServiceException {
        try {
            String algorithm = secretTopicKey.getAlgorithm();
            Cipher decipher = Cipher.getInstance(algorithm + "/" + mode + "/"
                    + padding, provider);
            IvParameterSpec spec = null; // initialization vector

            if (mode != "ECB") {
                spec = new IvParameterSpec(iv);
            }

            decipher.init(Cipher.DECRYPT_MODE, secretTopicKey, spec);
            byte[] decryptedPayloadBytes = decipher
                    .doFinal(encryptedPayloadBytes);
            return decryptedPayloadBytes;

        } catch (Exception e) {
            throw new ServiceException(moduleName
                    + "Problems decrypting payload" + e);
        }/* end try-catch */
    }

    public void testOpsOnPayload(SecretKey secretTopicKey, byte[] messageBytes,
            String mode, String padding, String provider)
            throws ServiceException {
        try {
            String algorithm = secretTopicKey.getAlgorithm();

            Cipher cipher = Cipher.getInstance(algorithm + "/" + mode + "/"
                    + padding, provider);
            IvParameterSpec spec = null; // initialization vector
            byte[] iv = null; // initialization vector as byte[]

            // ECB does not need an initialization vector others do.
            if (mode == "ECB") {
                cipher.init(Cipher.ENCRYPT_MODE, secretTopicKey);
            } else {
                // These modes need an iv with a valid block size in order
                // to be used.
                SecureRandom sr = new SecureRandom();
                // allocate memory for iv.
                iv = new byte[cipher.getBlockSize()];
                // Get next bytes from the PRNG.
                sr.nextBytes(iv);
                // create the IV class.
                spec = new IvParameterSpec(iv);
                // use encryption mode using specified key and IV.
                cipher.init(Cipher.ENCRYPT_MODE, secretTopicKey, spec);
            } /* end if-else */

            int outLength = cipher.getOutputSize(messageBytes.length);

            byte[] encryptedBytes = cipher.doFinal(messageBytes);
            System.out.println(moduleName + "Output bytes: " + outLength
                    + ", Encrypted Bytes: " + encryptedBytes.length);

            Cipher decipher = Cipher.getInstance(algorithm + "/" + mode + "/"
                    + padding, provider);
            decipher.init(Cipher.DECRYPT_MODE, secretTopicKey, spec);
            byte[] decryptedBytes = decipher.doFinal(encryptedBytes);

            System.out.println(moduleName + algorithm + "/" + mode + "/"
                    + padding + "\n decrypted: " + new String(decryptedBytes)
                    + "\n Output Length=" + decryptedBytes.length);
        } catch (Exception e) {
            throw new ServiceException(moduleName
                    + "Error while testing payload " + e);
        }

    }

    /** Method to sign a message with the entity's personal private key */
    public byte[] signPayload(byte[] message, PrivateKey personalPrivateKey)
            throws ServiceException {
        byte[] signatureBytes = null;
        try {
            Signature signature = Signature.getInstance("SHA1withRSA");
            /**
             * This can be optimized, since we don't need to perform this
             * initialization everytime, if we do indeed use the same private
             * key everytime.
             */
            signature.initSign(personalPrivateKey);

            signature.update(message);
            signatureBytes = signature.sign();
        } catch (Exception e) {
            throw new ServiceException(moduleName + "Error signing payload "
                    + e);
        }
        return signatureBytes;
    }

    /**
     * Validates the signature associated with an encrypted message to confirm
     * whether the message has been tampered with and also to check if the
     * publisher is an authorized one
     */
    public boolean validateSignature(byte[] signatureBytes, byte[] message,
            PublicKey publisherPublicKey) throws ServiceException {
        boolean verification = false;
        try {
            Signature signature = Signature.getInstance("SHA1withRSA");
            /**
             * This can be optimized, since we don't need to perform this
             * initialization everytime, if we do indeed use the same private
             * key everytime.
             */
            signature.initVerify(publisherPublicKey);
            signature.update(message);
            verification = signature.verify(signatureBytes);
        } catch (Exception e) {
            throw new ServiceException(moduleName
                    + "Error validating signature " + e);
        }
        return verification;
    }

    /** Method to sign a message with the entity's personal private key */
    public byte[] signPayload(byte[] payload, PrivateKey personalPrivateKey,
            String algorithm) throws ServiceException {
        byte[] signatureBytes = null;
        try {
            Signature signature = Signature.getInstance(algorithm);
            /**
             * This can be optimized, since we don't need to perform this
             * initialization everytime, if we do indeed use the same private
             * key everytime.
             */
            signature.initSign(personalPrivateKey);

            signature.update(payload);
            signatureBytes = signature.sign();
        } catch (Exception e) {
            throw new ServiceException(moduleName + "Error signing payload "
                    + e);
        }
        return signatureBytes;
    }

    /** Method to sign a message with the entity's personal private key */
    public byte[] signPayload(PrivateKey personalPrivateKey, String algorithm,
            String provider, byte[] payload) throws ServiceException {
        byte[] signatureBytes = null;
        try {
            Signature signature = Signature.getInstance(algorithm, provider);
            /**
             * This can be optimized, since we don't need to perform this
             * initialization everytime, if we do indeed use the same private
             * key everytime.
             */
            signature.initSign(personalPrivateKey);

            signature.update(payload);
            signatureBytes = signature.sign();
        } catch (Exception e) {
            throw new ServiceException(moduleName + "Error signing payload "
                    + e);
        }
        return signatureBytes;
    }

    /**
     * Validates the signature associated with an encrypted message to confirm
     * whether the message has been tampered with and also to check if the
     * publisher is an authorized one
     */
    public boolean validateSignature(byte[] payload, byte[] signatureBytes,
            PublicKey publisherPublicKey, String algorithm)
            throws ServiceException {
        boolean verification = false;
        try {
            Signature signature = Signature.getInstance(algorithm);
            /**
             * This can be optimized, since we don't need to perform this
             * initialization everytime, if we do indeed use the same private
             * key everytime.
             */
            signature.initVerify(publisherPublicKey);
            signature.update(payload);
            verification = signature.verify(signatureBytes);
        } catch (Exception e) {
            throw new ServiceException(moduleName
                    + "Error validating signature " + e);
        }
        return verification;
    }

    /**
     * Validates the signature associated with an encrypted message to confirm
     * whether the message has been tampered with and also to check if the
     * publisher is an authorized one
     */
    public boolean validateSignature(PublicKey publisherPublicKey,
            String algorithm, String provider, byte[] payload,
            byte[] signatureBytes) throws ServiceException {
        boolean verification = false;
        try {
            Signature signature = Signature.getInstance(algorithm, provider);
            /**
             * This can be optimized, since we don't need to perform this
             * initialization everytime, if we do indeed use the same private
             * key everytime.
             */
            signature.initVerify(publisherPublicKey);
            signature.update(payload);
            verification = signature.verify(signatureBytes);
        } catch (Exception e) {
            throw new ServiceException(moduleName
                    + "Error validating signature " + e);
        }
        return verification;
    }

    /** Generate a message digest for the message */
    public byte[] generateMessageDigest(byte[] encryptedMessage,
            String algorithm) throws ServiceException {
        byte[] computedDigest = null;
        try {
            MessageDigest digest = MessageDigest.getInstance(algorithm);
            digest.update(encryptedMessage);
            computedDigest = digest.digest();
        } catch (Exception e) {
            throw new ServiceException(moduleName
                    + "Error generating message digest " + e);
        }
        return computedDigest;
    }

    /** Check the message integrity */
    public boolean validateMessageDigest(byte[] originalDigest,
            byte[] encryptedMessage, String algorithm) throws ServiceException {
        boolean validation = false;
        try {
            MessageDigest digest = MessageDigest.getInstance(algorithm);
            digest.update(encryptedMessage);
            validation = MessageDigest.isEqual(digest.digest(), originalDigest);
        } catch (Exception e) {
            throw new ServiceException(moduleName
                    + "Error validating message digest " + e);
        }
        return validation;
    }

    /** Generate a message digest for the message */
    public byte[] generateMessageDigest(String algorithm, String provider,
            byte[] encryptedPayload) throws ServiceException {
        byte[] computedDigest = null;
        try {
            MessageDigest digest = MessageDigest.getInstance(algorithm,
                    provider);
            digest.update(encryptedPayload);
            computedDigest = digest.digest();
        } catch (Exception e) {
            throw new ServiceException(moduleName
                    + "Error generating message digest " + e);
        }
        return computedDigest;
    }

    /** Check the message integrity */
    public boolean validateMessageDigest(String algorithm, String provider,
            byte[] encryptedPayload, byte[] originalDigest)
            throws ServiceException {
        boolean validation = false;
        try {
            MessageDigest digest = MessageDigest.getInstance(algorithm,
                    provider);
            digest.update(encryptedPayload);
            validation = MessageDigest.isEqual(digest.digest(), originalDigest);
        } catch (Exception e) {
            throw new ServiceException(moduleName
                    + "Error validating message digest " + e);
        }
        return validation;
    }

    /** Validates the assertion speficied in the message */
    public boolean validateSAMLAssertion(String assertion) {
        return false;
    }

    public static void main(String[] args) {
        try {
            EntityOperationsImpl entityOperations = new EntityOperationsImpl();
            EntityKeyManagementImpl entityKeyMgmtImpl = new EntityKeyManagementImpl();

            KeyManagementServiceImpl kms = new KeyManagementServiceImpl();
            SecretKey secKey = kms.generateTemplateKey(12345, "AES", 128, null);

            KeyPair keyPair = entityKeyMgmtImpl.generatePersonalKeyPair("RSA",
                    1024, "CryptixCrypto", "1234");
            System.out.println(keyPair.getPublic());
            
            String testString = "Test String to determine if operations work ";
            byte[] testBytes = testString.getBytes();

            System.out.println("Encrypting payload!");

            // Provider name
            String provider = "CryptixCrypto";

            // Array of all secret ciphers
            String secret_algorithm[] = { "Blowfish", "CAST5", "DES", "DESede",
                    "Rijndael", "SKIPJACK", "Square", "TripleDES" };

            // Array of all secret cipher modes
            String mode[] = { "ECB", "CBC", "OFB" };

            // Array of all paddings
            String padding[] = { /* "None", "NoPadding", */"PKCS#5"
            /* ,"PKCS5Padding" */};

            // Loop through all paddings, modes and ciphers and run them
            for (int i = 0; i < secret_algorithm.length; i++) {
                for (int j = 0; j < mode.length; j++) {
                    for (int k = 0; k < padding.length; k++) {
                        System.out.println("Using:" + secret_algorithm[i] + "/"
                                + mode[j] + "/" + padding[k]);
                        try {
                            secKey = kms.generateSecretKey(secret_algorithm[i],
                                    provider);
                            entityOperations.testOpsOnPayload(secKey,
                                    testBytes, mode[j], padding[k], provider);
                        } catch (Exception e) {
                            System.out.println(e);
                        }
                        System.out.println("\n\n");
                    } // end for(k)
                } // end for(j)
            } // end for (i)

            /*
             * byte[] encryptedBytes = entityOperations.encryptPayload(secKey,
             * testBytes); byte[] decryptedBytes =
             * entityOperations.decryptPayload(secKey, encryptedBytes); String
             * decryptedString = new String(decryptedBytes);
             * System.out.println("Decrypted Message is \n" + decryptedString);
             * 
             * byte[] encryptedBytes =
             * entityOperations.encryptPayload(keyPair.getPublic(), testBytes);
             * byte[] decryptedBytes =
             * entityOperations.decryptPayload(keyPair.getPrivate(),
             * encryptedBytes);
             * 
             * String decryptedString = new String(decryptedBytes);
             * System.out.println("Decrypted Message is \n" + decryptedString);
             */
            byte[] encryptedBytes = "Testing message digest functions"
                    .getBytes();
            byte[] digest = entityOperations.generateMessageDigest(
                    encryptedBytes, "SHA");
            boolean digestVerify = entityOperations.validateMessageDigest(
                    digest, encryptedBytes, "SHA");
            if (digestVerify) {
                System.out.println("Digest Verification success ...");
            } else {
                System.out.println("Verification unsuccessful");
            }

            byte[] signatureBytes = entityOperations.signPayload(
                    encryptedBytes, keyPair.getPrivate());
            boolean verified = entityOperations.validateSignature(
                    signatureBytes, encryptedBytes, keyPair.getPublic());
            if (verified) {
                System.out.println("Signature Validation Success ...");
            } else {
                System.out.println("Signature NOT Validated ...");
            }

        } catch (ServiceException serEx) {
            System.out.println(serEx);
        } catch (Exception e) {
            System.out.println(e);
        }
    }

}

